﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using AvalonDock;
using AvalonDock.Layout;
using Shell.Library.Views;
using Catel;
using Catel.IoC;
using Catel.MVVM;
using Catel.Windows.Controls;
using Microsoft.Practices.Prism.Regions;

namespace Shell.Library.Helpers
{
    public class AvalonDockHelper
    {
        private static readonly DockingManager DockingManager;

        private static readonly LayoutDocumentPane LayoutDocumentPane;

        private static readonly LayoutAnchorablePane LayoutAnchorablePane;

        static AvalonDockHelper()
        {
            DockingManager = ServiceLocator.Default.ResolveType<DockingManager>();
            DockingManager.DocumentClosed += OnDockingManagerDocumentClosed;

            LayoutDocumentPane = ServiceLocator.Default.ResolveType<LayoutDocumentPane>();
            LayoutAnchorablePane = ServiceLocator.Default.ResolveType<LayoutAnchorablePane>();
        }

        #region Properties
        /// <summary>
        /// Gets the region manager.
        /// </summary>
        private static IRegionManager RegionManager
        {
            get { return ServiceLocator.Default.ResolveType<IRegionManager>(); }
        }
        #endregion

        #region Methods

        public static LayoutDocument FindDocument(Type viewType, object tag = null)
        {
            Argument.IsNotNull("viewType", viewType);

            return (from document in LayoutDocumentPane.Children
                    where document is LayoutDocument && document.Content.GetType() == viewType &&
                          TagHelper.AreTagsEqual(tag, ((IView)document.Content).Tag)
                    select document).Cast<LayoutDocument>().FirstOrDefault();
        }

        public static LayoutAnchorable FindToolBoxItem(Type viewType, object tag = null)
        {
            Argument.IsNotNull("viewType", viewType);

            return (from document in LayoutAnchorablePane.Children
                    where document != null && document.Content.GetType() == viewType &&
                          TagHelper.AreTagsEqual(tag, ((IView)document.Content).Tag)
                    select document).FirstOrDefault();
        }

        public static void ActivateDocument(LayoutDocument document)
        {
            Argument.IsNotNull("document", document);
            LayoutDocumentPane.SelectedContentIndex = LayoutDocumentPane.IndexOfChild(document);
        }

        public static void ActivateDocument(LayoutAnchorable document)
        {
            Argument.IsNotNull("document", document);
            LayoutAnchorablePane.SelectedContentIndex = LayoutDocumentPane.IndexOfChild(document);
        }

        public static LayoutAnchorable CreateToolBoxItem(FrameworkElement view, object tag = null)
        {
            Argument.IsNotNull("view", view);

            var layoutDocument = WrapViewInLayoutAnchorable(view, tag);

            LayoutAnchorablePane.Children.Add(layoutDocument);

            return layoutDocument;
        }

        private static LayoutAnchorable WrapViewInLayoutAnchorable(FrameworkElement view, object tag = null)
        {
            Argument.IsNotNull("view", view);
            Argument.IsNotNull("viewModel", view.DataContext);
            Argument.IsOfType(() => view.DataContext, typeof(IViewModel));

            var layoutDocument = new LayoutAnchorable();
            layoutDocument.CanFloat = false;
            layoutDocument.Title = ((IViewModel)view.DataContext).Title;
            layoutDocument.Content = view;

            ((IViewModel)view.DataContext).PropertyChanged += OnLayoutDocumentViewModelPropertyChanged(layoutDocument);

            view.Tag = tag;

            return layoutDocument;
        }

        private static PropertyChangedEventHandler OnLayoutDocumentViewModelPropertyChanged(LayoutAnchorable layoutDocument)
        {
            return (s, e) =>
            {
                if (e.PropertyName == "Title")
                {
                    layoutDocument.Title = ((IViewModel)s).Title;
                }
            };
        }

        public static LayoutDocument CreateDocument(FrameworkElement view, object tag = null)
        {
            Argument.IsNotNull("view", view);

            var layoutDocument = WrapViewInLayoutDocument(view, tag);

            LayoutDocumentPane.Children.Add(layoutDocument);

            return layoutDocument;
        }

        private static LayoutDocument WrapViewInLayoutDocument(FrameworkElement view, object tag = null)
        {
            Argument.IsNotNull("view", view);
            Argument.IsNotNull("viewModel", view.DataContext);
            Argument.IsOfType(() => view.DataContext, typeof(IViewModel));

            var layoutDocument = new LayoutDocument();
            layoutDocument.CanFloat = false;
            layoutDocument.Title = ((IViewModel)view.DataContext).Title;
            layoutDocument.Content = view;

            ((IViewModel)view.DataContext).PropertyChanged += OnLayoutDocumentViewModelPropertyChanged(layoutDocument);

            view.Tag = tag;

            return layoutDocument;
        }

        private static PropertyChangedEventHandler OnLayoutDocumentViewModelPropertyChanged(LayoutDocument layoutDocument)
        {
            return (s, e) =>
            {
                if (e.PropertyName == "Title")
                {
                    layoutDocument.Title = ((IViewModel)s).Title;
                }
            };
        }

        private static void OnDockingManagerDocumentClosed(object sender, DocumentClosedEventArgs e)
        {
            var containerView = e.Document;
            var view = containerView.Content as IDocumentView;
            if (view != null)
            {
                view.CloseDocument();
                ((IViewModel)view.DataContext).PropertyChanged -= OnLayoutDocumentViewModelPropertyChanged(containerView);
            }
        }
        #endregion
    }
}